home *** CD-ROM | disk | FTP | other *** search
/ Skunkware 5 / Skunkware 5.iso / src / X11 / spore / spore.c < prev    next >
C/C++ Source or Header  |  1995-05-03  |  28KB  |  920 lines

  1. /*
  2.  *    @(#) spore.c 1.3 93/11/02 MRINC
  3.  *
  4.  *    Written using CGI 10 Jun 1987 by Ron Record (rr@sco.com)
  5.  *    Rewritten using X11 07 Apr 1993 by Ron Record (rr@sco.com)
  6.  */
  7. /*************************************************************************
  8.  *                                                                       *
  9.  *  Copyright (c) 1987-1993 Ronald Joe Record                            *
  10.  *                                                                       *
  11.  *  All rights reserved. No part of this program or publication may be   *
  12.  *  reproduced, transmitted, transcribed, stored in a retrieval system,  *
  13.  *  or translated into any language or computer language, in any form or *
  14.  *  by any means, electronic, mechanical, magnetic, optical, chemical,   *
  15.  *  biological, or otherwise, without the prior written permission of:   *
  16.  *                                                                       *
  17.  *      Ronald Joe Record (408) 458-3718                                 *
  18.  *      212 Owen St., Santa Cruz, California 95062 USA                   *
  19.  *                                                                       *
  20.  *************************************************************************/
  21.  
  22.  
  23. #include "spore.h"
  24.  
  25. #define BMAX 1024
  26.  
  27. typedef struct {
  28.     int initial_x,initial_y;
  29.     int now_x, now_y;
  30.     int min_x, min_y;
  31.     int max_x, max_y;
  32.     int dx, dy;
  33. } BALL;
  34.  
  35. BALL balls[BMAX];
  36. int col_duration=350;
  37. int nballs=1;
  38. int  num, move;
  39. int stop=0;
  40. int spore_hue;
  41.  
  42. int width, height;
  43. int nummaps=1, delay=0, eternal=0;
  44. int demo=0, useroot=0, full=0, oflag=0, spin=0, center=0;
  45. int maxcolor, next;
  46. int **xy;
  47. char *outname;
  48.  
  49. /* routines declared in this file */
  50. void event_loop(), usage(), init_contexts();
  51. void Clear(), freemem(), setupmem(), init_pts(), print_help();
  52. void redisplay(), resize(), save(), aggregate(), parseargs(), Getkey(); 
  53. void Redraw();
  54. int checkit(), walk();
  55. /* external routines used in this file */
  56. extern long lrand48();
  57. extern void FlushBuffer(), BufferPoint(), InitBuffer();
  58.  
  59. void
  60. usage()
  61. {
  62.     printf("Usage: spore [-o file][-dsuFRTV]");
  63.     printf("[-m #][-w width][-h height]\n");
  64.     printf("\t-d indicates demo mode\n");
  65.     printf("\t-s indicates spin color wheel when done computing\n");
  66.     printf("\t-R indicates use the root window\n");
  67.     printf("\t-m # indicates a minimum color index of # (0-255)\n");
  68.     printf("\t-o file will save the output as 'file' in PPM format\n");
  69.     printf("\t-w # indicates a window width of #\n");
  70.     printf("\t-h # indicates a window height of #\n");
  71.     printf("\t-u produces this message\n");
  72.     printf("During display :\n");
  73.     printf("\t'f' or 'F' will save the picture as a PPM file\n");
  74.     printf("\t'+' will increment and '-' decrement the minimum color index\n");
  75.     printf("\t'r' or 's' will spin the color wheel forwards or backwards\n");
  76.     printf("\t'W' will increment and 'w' decrement the color map selection\n");
  77.     printf("\t'?' or 'h' will display the usage message\n");
  78.     printf("\t'q' or 'Q' will quit\n");
  79. }
  80.  
  81. void
  82. init_contexts()
  83. {
  84.     static int i;
  85.  
  86.     /*
  87.      * create default, writable, graphics contexts for the canvas.
  88.      */
  89.     Data_GC[0] = XCreateGC(dpy, DefaultRootWindow(dpy),
  90.         (unsigned long) NULL, (XGCValues *) NULL);
  91.     /* set the background to black */
  92.     XSetBackground(dpy,Data_GC[0],BlackPixel(dpy, screen));
  93.     /* set the foreground of the 0th context to black */
  94.     XSetForeground(dpy, Data_GC[0], BlackPixel(dpy, screen));
  95.     Data_GC[1] = XCreateGC(dpy, DefaultRootWindow(dpy),
  96.         (unsigned long) NULL, (XGCValues *) NULL);
  97.     /* set the background to black */
  98.     XSetBackground(dpy,Data_GC[1],BlackPixel(dpy, screen));
  99.     /* set the foreground of the 1st context to white */
  100.     XSetForeground(dpy, Data_GC[1], WhitePixel(dpy,  screen));
  101.     for (i=2; i<maxcolor; i++) {
  102.         Data_GC[i] = XCreateGC(dpy, DefaultRootWindow(dpy),
  103.             (unsigned long) NULL, (XGCValues *) NULL);
  104.         /* set the background to black */
  105.         XSetBackground(dpy,Data_GC[i],BlackPixel(dpy, screen));
  106.         /* set the foreground of the ith context to i */
  107.         XSetForeground(dpy, Data_GC[i], i);
  108.     }
  109. }
  110.  
  111. void
  112. Clear()
  113. {
  114.     XFillRectangle(dpy, pixmap, Data_GC[0], 0, 0, width, height);
  115.     XCopyArea(dpy, pixmap, canvas, Data_GC[0], 0, 0, width, height, 0, 0);
  116. }
  117.  
  118. void
  119. freemem()
  120. {
  121.     static int i;
  122.  
  123.     for (i=0;i<=width;i++)
  124.         free(xy[i]);
  125.     free(xy);
  126. }
  127.  
  128. void
  129. setupmem()
  130. {
  131.     static int i;
  132.  
  133.     if ((xy=(int **)malloc((width+1)*sizeof(int *))) == (int **)NULL) {
  134.         printf("Error malloc'ing xy.\n");
  135.         exit (-1);
  136.     }
  137.     for (i=0;i<width+1;i++) {
  138.         if ((xy[i]=(int *)malloc((height+1)*sizeof(int)))==(int *)NULL){
  139.             printf("Error malloc'ing xy[%d].\n", i);
  140.             exit (-1);
  141.         }
  142.     }
  143. }
  144.  
  145. void 
  146. init_ball(k)
  147. int k;
  148. {
  149.     static int i, j, outside;
  150.  
  151.     if (center) {
  152.         i = ((k/2) % 2) ? 1 : -1;
  153.         j = (k % 2) ? 1 : -1;
  154.         balls[k].initial_x=(width/2) + (j * (k*width)/(4*nballs));
  155.         balls[k].now_x=balls[k].initial_x;
  156.         balls[k].initial_y=(height/2) + (i * (k*height)/(4*nballs));
  157.         balls[k].now_y = balls[k].initial_y;
  158.         balls[k].min_x = balls[k].now_x - 2; 
  159.         balls[k].min_y = balls[k].now_y - 2;
  160.         balls[k].max_x = balls[k].now_x + 2; 
  161.         balls[k].max_y = balls[k].now_y + 2;
  162.         balls[k].dx = 4; balls[k].dy = 4;
  163.     }
  164.     else {
  165.         for(i=0;i<MAX_ATTEMPTS;i++) {
  166.             balls[k].initial_x = (lrand48()%(width/2))+(width/4);
  167.             balls[k].initial_y = (lrand48() % (height/2)) + (height/4);
  168.             outside = 1;
  169.             for (j=0; j<nballs; j++) {
  170.               if (!(stop || (k == j)))
  171.                 if ((balls[k].initial_x > balls[j].min_x) ||
  172.                     (balls[k].initial_x < balls[j].max_x) ||
  173.                     (balls[k].initial_y < balls[j].max_y) ||
  174.                     (balls[k].initial_y > balls[j].min_y))
  175.                     outside = 0;
  176.             }
  177.             if (outside)
  178.                 break;
  179.         }
  180.         balls[k].now_x = balls[k].initial_x;
  181.         balls[k].now_y = balls[k].initial_y;
  182.         balls[k].min_x = balls[k].now_x - 2; 
  183.         balls[k].min_y = balls[k].now_y - 2;
  184.         balls[k].max_x = balls[k].now_x + 2; 
  185.         balls[k].max_y = balls[k].now_y + 2;
  186.         balls[k].dx = 4; balls[k].dy = 4;
  187.     }
  188.     xy[balls[k].now_x][balls[k].now_y] = spore_hue;
  189.     BufferPoint(dpy, canvas, pixmap, Data_GC, &Points, spore_hue, 
  190.                     balls[k].now_x, height - balls[k].now_y - 1);
  191. }
  192.  
  193. void
  194. init_pts()
  195. {
  196.     static int i, j;
  197.  
  198.     for (i=0; i<width+1; i++)
  199.         for (j=0; j<height+1; j++)
  200.             xy[i][j] = 0;
  201.     for (i=0;i<nballs;i++)
  202.         init_ball(i);
  203. }
  204.  
  205. initialize()
  206. {
  207.     InitBuffer(&Points, maxcolor);
  208.     Clear();
  209.     init_pts();
  210.     num = 1;
  211. }
  212.  
  213. #define x_str 10
  214.  
  215. void
  216. print_help() 
  217. {
  218.     static char str[80];
  219.     static int y_str, spacing;
  220.     static int ascent, descent, dir;
  221.     static XCharStruct overall;
  222.     static GC gc;
  223.  
  224.     gc = Data_GC[1];
  225.     XClearWindow(dpy, help);
  226.     y_str = 60;
  227.     sprintf(str,"During run-time, interactive control can be exerted via : ");
  228.     XDrawImageString(dpy,help,gc,x_str,y_str,str,strlen(str));
  229.     XQueryTextExtents(dpy,(XID)XGContextFromGC(gc),"Hey!",
  230.             4,&dir,&ascent,&descent,&overall);
  231.     spacing = ascent + descent + 5;
  232.     y_str += 2 * spacing;
  233.     sprintf(str,"        - lowers the value of mincolindex, + raises it");
  234.     XDrawImageString(dpy,help,gc,x_str,y_str,str,strlen(str));
  235.     y_str += spacing;
  236.     sprintf(str,"        c deletes the last spore unless there's only one");
  237.     XDrawImageString(dpy,help,gc,x_str,y_str,str,strlen(str));
  238.     y_str += spacing;
  239.     sprintf(str,"        C creates a new spore");
  240.     XDrawImageString(dpy,help,gc,x_str,y_str,str,strlen(str));
  241.     y_str += spacing;
  242.     sprintf(str,"        d decreases the delay, D increases it");
  243.     XDrawImageString(dpy,help,gc,x_str,y_str,str,strlen(str));
  244.     y_str += spacing;
  245.     sprintf(str,"        e toggles continuous creation of new spores");
  246.     XDrawImageString(dpy,help,gc,x_str,y_str,str,strlen(str));
  247.     y_str += spacing;
  248.     sprintf(str,"        f or F saves spore to a PPM file");
  249.     XDrawImageString(dpy,help,gc,x_str,y_str,str,strlen(str));
  250.     y_str += spacing;
  251.     sprintf(str,"        h or H or ? displays this message");
  252.     XDrawImageString(dpy,help,gc,x_str,y_str,str,strlen(str));
  253.     y_str += spacing;
  254.     sprintf(str,"        n goes on to the next spore");
  255.     XDrawImageString(dpy,help,gc,x_str,y_str,str,strlen(str));
  256.     y_str += spacing;
  257.     sprintf(str,"        N goes on to the next spore without increment");
  258.     XDrawImageString(dpy,help,gc,x_str,y_str,str,strlen(str));
  259.     y_str += spacing;
  260.     sprintf(str,"        r or s spins the colorwheel, R or S stops the spin");
  261.     XDrawImageString(dpy,help,gc,x_str,y_str,str,strlen(str));
  262.     y_str += spacing;
  263.     sprintf(str,"        w decrements, W increments the color wheel index");
  264.     XDrawImageString(dpy,help,gc,x_str,y_str,str,strlen(str));
  265.     y_str += spacing;
  266.     sprintf(str,"        <ctrl>-W reads the color palette in $HOME/.sporemap");
  267.     XDrawImageString(dpy,help,gc,x_str,y_str,str,strlen(str));
  268.     y_str += spacing;
  269.     sprintf(str,"        q or Q exits");
  270.     XDrawImageString(dpy,help,gc,x_str,y_str,str,strlen(str));
  271.     y_str += 2*spacing;
  272.     sprintf(str,"Press 'h', 'H', or '?' to unmap the help window");
  273.     XDrawImageString(dpy,help,gc,x_str,y_str,str,strlen(str));
  274. }
  275.  
  276. void
  277. redisplay (event)
  278. XExposeEvent    *event;
  279. {
  280.     if ((event->window == help) && (!useroot))
  281.         print_help();
  282.     else {
  283.         /*
  284.         * Extract the exposed area from the event and copy
  285.         * from the saved pixmap to the window.
  286.         */
  287.         XCopyArea(dpy, pixmap, canvas, Data_GC[0], event->x, event->y, 
  288.             event->width, event->height, event->x, event->y);
  289.     }
  290. }
  291.  
  292. void
  293. resize()
  294. {
  295.     Window r;
  296.     int j; 
  297.     int x, y;
  298.     unsigned int bw, d, new_w, new_h;
  299.  
  300.     freemem();
  301.     XGetGeometry(dpy,canvas,&r,&x,&y,&new_w,&new_h,&bw,&d);
  302.     if (((int)new_w == width) && ((int)new_h == height)) {
  303.         setupmem();
  304.         return;
  305.     }
  306.     width = (int)new_w; height = (int)new_h;
  307.     if (pixmap)
  308.         XFreePixmap(dpy, pixmap);
  309.     pixmap = XCreatePixmap(dpy, DefaultRootWindow(dpy), 
  310.             width, height, DefaultDepth(dpy, screen));
  311.     setupmem();
  312.     next = 1;
  313.     stop = 0;
  314.     nummaps++;
  315.     initialize();
  316. }
  317.  
  318. void
  319. Cleanup() {
  320.     freemem();
  321.     XCloseDisplay(dpy);
  322. }
  323.  
  324. /* Store spore growth in PPM format */
  325. void
  326. save()
  327. {
  328.     FILE *outfile;
  329.     unsigned char c;
  330.     XImage *ximage;
  331.     static int i,j;
  332.     struct Colormap {
  333.         unsigned char red;
  334.         unsigned char green;
  335.         unsigned char blue;
  336.     };
  337.     struct Colormap *colormap=NULL;
  338.  
  339.     if ((colormap=
  340.         (struct Colormap *)malloc(sizeof(struct Colormap)*maxcolor))
  341.             == NULL) {
  342.         fprintf(stderr,"Error malloc'ing colormap array\n");
  343.         Cleanup();
  344.         exit(-1);
  345.     }
  346.     outfile = fopen(outname,"w");
  347.     if(!outfile) {
  348.         perror(outname);
  349.         Cleanup();
  350.         exit(-1);
  351.     }
  352.  
  353.     ximage=XGetImage(dpy, pixmap, 0, 0, width, height, AllPlanes, ZPixmap);
  354.  
  355.     for (i=0;i<maxcolor;i++) {
  356.         colormap[i].red=(unsigned char)(Colors[i].red >> 8);
  357.         colormap[i].green=(unsigned char)(Colors[i].green >> 8);
  358.         colormap[i].blue =(unsigned char)(Colors[i].blue >> 8);
  359.     }
  360.     fprintf(outfile,"P%d %d %d\n",6,width,height);
  361.     fprintf(outfile,"%d\n",maxcolor-1);
  362.  
  363.     for (j=0;j<height;j++)
  364.         for (i=0;i<width;i++) {
  365.             c = (unsigned char)XGetPixel(ximage,i,j);
  366.             fwrite((char *)&colormap[c],sizeof colormap[0],1,outfile);
  367.         }
  368.     fclose(outfile);
  369.     free(colormap);
  370. }
  371.  
  372. void
  373. Redraw() {
  374.     static int i, j;
  375.  
  376.     FlushBuffer(dpy, canvas, pixmap, Data_GC, &Points, 0, maxcolor);
  377.     Clear();
  378.     for (i=0; i < width; i++)
  379.         for (j=0; j < height; j++)
  380.             if (xy[i][j])
  381.                 BufferPoint(dpy, canvas, pixmap, Data_GC, &Points, xy[i][j], 
  382.                             i, height - j - 1);
  383.     FlushBuffer(dpy, canvas, pixmap, Data_GC, &Points, 0, maxcolor);
  384. }
  385.  
  386. void
  387. Getkey(event)
  388. XKeyEvent *event;
  389. {
  390.     char key;
  391.     static int spinning=0, spindir=0;
  392.     static XWindowAttributes attr;
  393.     extern void write_cmap(), init_color();
  394.  
  395.     if (XLookupString(event, (char *)&key, sizeof(key), (KeySym *)0,
  396.        (XComposeStatus *) 0) > 0)
  397.             switch (key) {
  398.                 case '\015': /*write out current colormap to $HOME/.<prog>map*/
  399.                     write_cmap(dpy,cmap,Colors,maxcolor,"spore","Spore");
  400.                     break;
  401.                 case '+': mincolindex += INDEXINC;
  402.                     if (mincolindex > maxcolor)
  403.                         mincolindex = 1;
  404.                     init_color(dpy,canvas,cmap,Colors,STARTCOLOR,
  405.                             mincolindex,maxcolor,numwheels,"spore","Spore",0);
  406.                     break;
  407.                 case '-': mincolindex -= INDEXINC;
  408.                     if (mincolindex < 1)
  409.                         mincolindex = maxcolor - 1;
  410.                     init_color(dpy,canvas,cmap,Colors,STARTCOLOR,
  411.                             mincolindex,maxcolor,numwheels,"spore","Spore",0);
  412.                     break;
  413.                 case 'c':    /* delete last spore unless there's only one */
  414.                         if (nballs > 1)
  415.                             nballs--;
  416.                         break;
  417.                 case 'C':    /* create a new spore, leaving the old */
  418.                         center = 0;
  419.                         if (stop) { /* finished with current aggregate */
  420.                             next = 1;
  421.                             nummaps++;
  422.                             init_ball(lrand48()%nballs); /* re-do one of them */
  423.                         }
  424.                         else {                    /* still computing current */
  425.                             nballs++;            /* increment number of spores */
  426.                             init_ball(nballs-1);/* initialize new spore */
  427.                         }
  428.                         break;
  429.                 case 'd': delay -= 25; if (delay < 0) delay = 0; break;
  430.                 case 'D': delay += 25; break;
  431.                 case 'e': eternal = (!eternal);
  432.                           if (eternal) {
  433.                             center = 0;
  434.                             next = 1;
  435.                             nummaps++;
  436.                             init_ball(lrand48()%nballs); /* re-do one of them */
  437.                           }
  438.                         break;
  439.                 case 'f':    /* save in PPM format file */
  440.                 case 'F': save(); break;
  441.                 case 'n':    /* go on to the next spore */
  442.                     next = 1;
  443.                     initialize();
  444.                     break;
  445.                 case 'N':    /* go on to the next spore */
  446.                     nummaps++;    /* but don't increment the spore counter */
  447.                     next = 1;
  448.                     break;
  449.                 case 'S':
  450.                 case 'R': spinning=0;
  451.                     break;
  452.                 case 'r': spinning=1; spindir=1; 
  453.                     Spin(dpy, cmap, Colors, STARTCOLOR, maxcolor, delay, 1);
  454.                     break;
  455.                 case 's': spinning=1; spindir=0;
  456.                     Spin(dpy, cmap, Colors, STARTCOLOR, maxcolor, delay, 0);
  457.                     break;
  458.                 case '\027': /* (ctrl-W) read palette from $HOME/.sporemap */
  459.                   numwheels = 0;
  460.                   init_color(dpy,canvas,cmap,Colors,STARTCOLOR,
  461.                             mincolindex,maxcolor,numwheels,"spore","Spore",0);
  462.                   break;
  463.                 case 'W': 
  464.                     if (numwheels < MAXWHEELS)
  465.                         numwheels++;
  466.                     else
  467.                         numwheels = 0;
  468.                     init_color(dpy,canvas,cmap,Colors,STARTCOLOR,
  469.                             mincolindex,maxcolor,numwheels,"spore","Spore",0);
  470.                     break;
  471.                 case 'w': 
  472.                     if (numwheels > 0)
  473.                         numwheels--;
  474.                     else
  475.                         numwheels = MAXWHEELS;
  476.                     init_color(dpy,canvas,cmap,Colors,STARTCOLOR,
  477.                             mincolindex,maxcolor,numwheels,"spore","Spore",0);
  478.                     break;
  479.                 case '?':
  480.                 case 'h': 
  481.                     if (!useroot) {
  482.                         XGetWindowAttributes(dpy, help, &attr);
  483.                         if (attr.map_state != IsUnmapped)
  484.                             XUnmapWindow(dpy, help);
  485.                         else {
  486.                             XMapRaised(dpy, help);
  487.                             print_help();
  488.                         }
  489.                     }
  490.                     break;
  491.                 case 'X':    /* create new spores, erasing the old */
  492.                         next = stop = 1;
  493.                         nummaps++;
  494.                         FlushBuffer(dpy, canvas, pixmap, Data_GC, &Points, 
  495.                                         0, maxcolor);
  496.                         initialize();
  497.                         break;
  498.                 case 'Q':
  499.                 case 'q': Cleanup(); exit(0); break;
  500.             }
  501.             if (spinning)
  502.                 Spin(dpy, cmap, Colors, STARTCOLOR, maxcolor, delay, spindir);
  503. }
  504.  
  505. void
  506. parseargs(argc, argv)
  507. int argc;
  508. char *argv[];
  509. {
  510.     int c;
  511.     extern int optind, getopt();
  512.     extern char *optarg;
  513.  
  514.     outname = "spore.ppm";
  515.     width = 512; height = 480;
  516.     while((c = getopt(argc, argv, "desuCFRTVc:h:k:m:n:o:w:D:N:")) != EOF)
  517.     {    switch(c)
  518.         {
  519.         case 'c':
  520.             numwheels = atoi(optarg);
  521.             if (numwheels > MAXWHEELS)
  522.                 numwheels = MAXWHEELS;
  523.             if (numwheels < 0)
  524.                 numwheels = 0;
  525.             break;
  526.         case 'd':
  527.             demo++;
  528.             break;
  529.         case 'e':
  530.             eternal++;
  531.             break;
  532.         case 'u':
  533.             usage();
  534.             exit(0);
  535.         case 'h':
  536.             height = atoi(optarg);
  537.             break;
  538.         case 'k':
  539.             col_duration = atoi(optarg);
  540.             break;
  541.         case 'm':
  542.             mincolindex = atoi(optarg);
  543.             break;
  544.         case 'n':
  545.             nummaps = atoi(optarg);
  546.             break;
  547.         case 'o':
  548.             ++oflag;
  549.             outname = optarg;
  550.             break;
  551.         case 's':
  552.             ++spin;
  553.             break;
  554.         case 'w':
  555.             width = atoi(optarg);
  556.             break;
  557.         case 'C':
  558.             center++;
  559.             break;
  560.         case 'F':
  561.             full++;
  562.             break;
  563.         case 'D':
  564.             delay = atoi(optarg);
  565.             break;
  566.         case 'N':
  567.             nballs = atoi(optarg);
  568.             break;
  569.         case 'R':
  570.             useroot++;
  571.             break;
  572.         case '?':
  573.             usage();
  574.             exit(1);
  575.             break;
  576.         }
  577.     }
  578. }
  579.  
  580. void
  581. event_loop()
  582. {
  583.     int n;
  584.     XEvent event;
  585.  
  586.     n = XEventsQueued(dpy, QueuedAfterFlush);
  587.     while (n-- > 0) {
  588.         XNextEvent(dpy, &event);
  589.         switch(event.type) {
  590.             case KeyPress:
  591.                 Getkey(&event);
  592.                 break;
  593.             case Expose:
  594.                 redisplay(&event);
  595.                 break;
  596.             case ConfigureNotify:
  597.                 resize();
  598.                 break;
  599.         }
  600.     }
  601. }
  602.  
  603. int
  604. checkit(q) 
  605. int q;
  606. {
  607.     static int i, j;
  608.  
  609.     for (i=0;i<3;i++)
  610.         for (j=0;j<3;j++)
  611.             if (xy[(balls[q].now_x)+i-1][(balls[q].now_y)+j-1])
  612.                 return(0);
  613.     return(1);
  614. }
  615.  
  616. int
  617. walk(x,y,z)
  618. int x,y,z;
  619. {
  620.     balls[z].now_x = x;
  621.     balls[z].now_y = y;
  622.     if (checkit(z) == 0)
  623.         return(0);
  624.     for(;;) {
  625.         move = lrand48() % 3;
  626.         if (balls[z].now_x > balls[z].initial_x) {
  627.             if (balls[z].now_y > balls[z].initial_y) {
  628.                 switch(move) {
  629.                 case 0: balls[z].now_x--; break;
  630.                 case 1: balls[z].now_x--; balls[z].now_y--; break;
  631.                 case 2: balls[z].now_y--; break;
  632.                 }
  633.             }
  634.             else if (balls[z].now_y < balls[z].initial_y) {
  635.                 switch(move) {
  636.                 case 0: balls[z].now_x--; break;
  637.                 case 1: balls[z].now_x--; balls[z].now_y++; break;
  638.                 case 2: balls[z].now_y++; break;
  639.                 }
  640.             }
  641.             else {
  642.                 switch(move) {
  643.                 case 0: balls[z].now_x--; balls[z].now_y--; break;
  644.                 case 1: balls[z].now_x--; break;
  645.                 case 2: balls[z].now_x--; balls[z].now_y++; break;
  646.                 }
  647.             }
  648.         }
  649.         else if (balls[z].now_x < balls[z].initial_x) {
  650.             if (balls[z].now_y > balls[z].initial_y) {
  651.                 switch(move) {
  652.                 case 0: balls[z].now_x++; break;
  653.                 case 1: balls[z].now_x++; balls[z].now_y--; break;
  654.                 case 2: balls[z].now_y--; break;
  655.                 }
  656.             }
  657.             else if (balls[z].now_y < balls[z].initial_y) {
  658.                 switch(move) {
  659.                 case 0: balls[z].now_y++; break;
  660.                 case 1: balls[z].now_y++; balls[z].now_x++; break;
  661.                 case 2: balls[z].now_x++; break;
  662.                 }
  663.             }
  664.             else {
  665.                 switch(move) {
  666.                 case 0: balls[z].now_x++; balls[z].now_y++; break;
  667.                 case 1: balls[z].now_x++; break;
  668.                 case 2: balls[z].now_x++; balls[z].now_y--; break;
  669.                 }
  670.             }
  671.         }
  672.         else {
  673.             if (balls[z].now_y > balls[z].initial_y) {
  674.                 switch(move) {
  675.                 case 0: balls[z].now_x--; balls[z].now_y--; break;
  676.                 case 1: balls[z].now_y--; break;
  677.                 case 2: balls[z].now_x++; balls[z].now_y--; break;
  678.                 }
  679.             }
  680.             else {
  681.                 switch(move) {
  682.                 case 0: balls[z].now_x--; balls[z].now_y++; break;
  683.                 case 1: balls[z].now_y++; break;
  684.                 case 2: balls[z].now_y++; balls[z].now_x++; break;
  685.                 }
  686.             }
  687.         }
  688.         if (checkit(z) == 0)
  689.             return(0);
  690.     }
  691. }
  692.  
  693. adjust_box(k)
  694. int k;
  695. {
  696.     if ((balls[k].now_y <= balls[k].min_y) && (balls[k].now_y > 1)) {
  697.         balls[k].min_y = balls[k].now_y - 1;
  698.         balls[k].dy = balls[k].max_y - balls[k].min_y;
  699.     }
  700.     if ((balls[k].now_x <= balls[k].min_x) && (balls[k].now_x > 1)) {
  701.         balls[k].min_x = balls[k].now_x - 1;
  702.         balls[k].dx = balls[k].max_x - balls[k].min_x;
  703.     }
  704.     if ((balls[k].now_y >= balls[k].max_y) && (balls[k].now_y < height - 1)) {
  705.         balls[k].max_y = balls[k].now_y + 1;
  706.         balls[k].dy = balls[k].max_y - balls[k].min_y;
  707.     }
  708.     if ((balls[k].now_x >= balls[k].max_x) && (balls[k].now_x < width - 1)) {
  709.         balls[k].max_x = balls[k].now_x + 1;
  710.         balls[k].dx = balls[k].max_x - balls[k].min_x;
  711.     }
  712. }
  713.  
  714. void
  715. aggregate() 
  716. {
  717.     static int k, enter_x, enter_y;
  718.  
  719.     for (k=0;k<nballs;k++) {
  720.         move = lrand48() % 4;
  721.         switch(move) {
  722.         case 0:    /* entry on top border */
  723.             enter_x = (lrand48() % balls[k].dx) + balls[k].min_x;
  724.             enter_y = balls[k].min_y;
  725.             break;
  726.         case 1:    /* entry on bottom border */
  727.             enter_x = (lrand48() % balls[k].dx) + balls[k].min_x;
  728.             enter_y = balls[k].max_y;
  729.             break;
  730.         case 2:    /* entry on left border */
  731.             enter_y = (lrand48() % balls[k].dy) + balls[k].min_y;
  732.             enter_x = balls[k].min_x;
  733.             break;
  734.         case 3:    /* entry on right border */
  735.             enter_y = (lrand48() % balls[k].dy) + balls[k].min_y;
  736.             enter_x = balls[k].max_x;
  737.             break;
  738.         }
  739.         if (xy[enter_x][enter_y])
  740.             continue;
  741.         walk(enter_x,enter_y,k);
  742.         if (xy[balls[k].now_x][balls[k].now_y])
  743.             continue;
  744.         adjust_box(k);
  745.         xy[balls[k].now_x][balls[k].now_y] = spore_hue;
  746.         BufferPoint(dpy, canvas, pixmap, Data_GC, &Points, spore_hue, 
  747.                     balls[k].now_x, height - balls[k].now_y - 1);
  748.         if ((balls[k].now_y >= height-1) || (balls[k].now_x >= width-1)) {
  749.             num = 1;
  750.             stop=1;
  751.         }
  752.         if ((balls[k].now_y <= 1) || (balls[k].now_x <= 1)) {
  753.             num = 1;
  754.             stop=1;
  755.         }
  756.     }
  757. }
  758.  
  759. main(argc,argv)
  760. int argc;
  761. char *argv[];
  762. {
  763.     static int i, j;
  764.     static int count;
  765.     XSizeHints hint;
  766.     Atom __SWM_VROOT = None;
  767.     Window rootReturn, parentReturn, *children;
  768.     unsigned int numChildren;
  769.     extern void srand48(), init_color();
  770.     
  771.     parseargs(argc,argv);
  772.     srand48((long)time(0));
  773.     dpy = XOpenDisplay("");
  774.     screen = DefaultScreen(dpy);
  775.     if (full || useroot) {
  776.         width = XDisplayWidth(dpy, screen);
  777.         height = XDisplayHeight(dpy, screen);
  778.     }
  779.     maxcolor  = (int)XDisplayCells(dpy, screen);
  780.     if (maxcolor <= 16) {
  781.         STARTCOLOR = 2; delay = 100;
  782.         INDEXINC = 1; mincolindex = 5;
  783.     }
  784.     maxcolor = Min(maxcolor, MAXCOLOR);
  785.     spore_hue = STARTCOLOR;
  786.     /*
  787.     * Create the pixmap to hold the spore growth
  788.     */
  789.     pixmap = XCreatePixmap(dpy, DefaultRootWindow(dpy), width, height, 
  790.                            DefaultDepth(dpy, screen));
  791.     /*
  792.     * Create the window to display the fractal topographic map
  793.     */
  794.     hint.x = 0;
  795.     hint.y = 0;
  796.     hint.width = width;
  797.     hint.height = height;
  798.     hint.flags = PPosition | PSize;
  799.     if (useroot) {
  800.         canvas = DefaultRootWindow(dpy);
  801.         /* search for virtual root (from ssetroot by Tom LaStrange) */
  802.         __SWM_VROOT = XInternAtom(dpy, "__SWM_VROOT", False);
  803.         XQueryTree(dpy,canvas,&rootReturn,&parentReturn,&children,&numChildren);
  804.         for (j = 0; j < numChildren; j++) {
  805.             Atom actual_type;
  806.             int actual_format;
  807.             long nitems, bytesafter;
  808.             Window *newRoot = NULL;
  809.  
  810.             if (XGetWindowProperty (dpy, children[j], __SWM_VROOT,0,1, False, 
  811.                 XA_WINDOW, &actual_type, &actual_format, &nitems, &bytesafter,
  812.                 (unsigned char **) &newRoot) == Success && newRoot) {
  813.                 canvas = *newRoot;
  814.                 break;
  815.             }
  816.         }
  817.     }
  818.     else {
  819.         canvas = XCreateSimpleWindow(dpy, DefaultRootWindow(dpy),
  820.             0, 0, width, height, 5, 0, 1);
  821.         XSetStandardProperties(dpy, canvas, "Spore by Ron Record",
  822.             "Spore", None, argv, argc, &hint);
  823.         XMapRaised(dpy, canvas);
  824.     }
  825.     XChangeProperty(dpy, canvas, XA_WM_CLASS, XA_STRING, 8, PropModeReplace, 
  826.                     "spore", strlen("spore"));
  827.     /*
  828.     * Create the window used to display the help info (if not running on root)
  829.     */
  830.     if (!useroot) {
  831.         hint.x = XDisplayWidth(dpy, screen) / 4;
  832.         hint.y = XDisplayHeight(dpy, screen) / 4;
  833.         hint.width = hint.x * 2;
  834.         hint.height = hint.y * 2;
  835.         help = XCreateSimpleWindow(dpy, DefaultRootWindow(dpy),
  836.                 hint.x, hint.y, hint.width, hint.height, 5, 0, 1);
  837.         XSetWindowBackground(dpy, help, BlackPixel(dpy, screen));
  838.         /* Title */
  839.         XSetStandardProperties(dpy,help,"Help","Help",None,argv,argc,&hint);
  840.         /* Try to write into a new color map */
  841.         cmap = XCreateColormap(dpy,canvas,DefaultVisual(dpy,screen),AllocAll);
  842.         init_color(dpy, canvas, cmap, Colors, STARTCOLOR, mincolindex, maxcolor,
  843.                 numwheels,"spore", "Spore", 0);
  844.         /* install new color map */
  845.         XSetWindowColormap(dpy, canvas, cmap);
  846.     }
  847.     init_contexts();
  848.     setupmem();
  849.     if (useroot)
  850.         XSelectInput(dpy,canvas,ExposureMask);
  851.     else {
  852.         XSelectInput(dpy,canvas,KeyPressMask|ExposureMask|StructureNotifyMask);
  853.         XSelectInput(dpy,help,KeyPressMask|ExposureMask);
  854.     }
  855.     for (i=0; i!=nummaps; i++) {
  856.         next = 0;
  857.         if (!stop)    /* true 1st time thru */
  858.             initialize();
  859.         stop=0;
  860.         FlushBuffer(dpy,canvas,pixmap,Data_GC,&Points,spore_hue,spore_hue+1);
  861.         for (;;) {
  862.             event_loop();
  863.             aggregate();
  864.             if (stop) {
  865.               if (eternal) {
  866.                 center = 0;
  867.                 next = 1;
  868.                 nummaps++;
  869.                 init_ball(lrand48()%nballs); /* re-do one of them */
  870.               }
  871.               break;
  872.             }
  873.             if ((num % col_duration) == 0) {
  874.               FlushBuffer(dpy,canvas,pixmap,Data_GC,&Points,
  875.                             spore_hue,spore_hue+1);
  876.               spore_hue++; 
  877.               num=0;
  878.               if (spore_hue >= maxcolor)
  879.                 spore_hue = STARTCOLOR;
  880.             }
  881.             num++;
  882.         }
  883.         FlushBuffer(dpy,canvas,pixmap,Data_GC,&Points,0,maxcolor);
  884.         if (oflag)
  885.             save();
  886.         if (demo) {
  887.             event_loop();
  888.             DemoSpin(dpy, cmap, Colors, STARTCOLOR, maxcolor, delay, 4);
  889.             event_loop();
  890.             for (j=0; j<=MAXWHEELS; j++) {
  891.                 init_color(dpy, canvas, cmap, Colors, STARTCOLOR, mincolindex, 
  892.                         maxcolor, i, "spore", "Spore", 0);
  893.                 event_loop();
  894.                 sleep(1);
  895.             }
  896.         }
  897.         else if (useroot) {
  898.             XSetWindowBackgroundPixmap(dpy, canvas, pixmap);
  899.             for (i=0; i<maxcolor; i++)
  900.                 XFreeGC(dpy, Data_GC[i]);
  901.             XFreePixmap(dpy, pixmap);
  902.             XClearWindow(dpy, canvas);
  903.             XFlush(dpy);
  904.             Cleanup(); 
  905.             exit(0);
  906.         }
  907.         else {
  908.             XSync(dpy, True);
  909.             if (spin)
  910.                 Spin(dpy, cmap, Colors, STARTCOLOR, maxcolor, delay, 0);
  911.             for (;;) {
  912.                 event_loop();
  913.                 if (next) break;
  914.             }
  915.         }
  916.     }
  917.     Cleanup();
  918.     exit(0);
  919. }
  920.